package com.excilys.formation.projet.ebanking.webapp.controller;

import java.security.AccessControlException;

import javax.servlet.ServletRequest;
import javax.validation.Valid;

import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.excilys.formation.projet.ebanking.modele.Compte;
import com.excilys.formation.projet.ebanking.service.api.IClientService;
import com.excilys.formation.projet.ebanking.service.api.ICompteService;
import com.excilys.formation.projet.ebanking.service.api.exception.SoldeInsuffisantException;
import com.excilys.formation.projet.ebanking.webapp.date.MonthPickerEnable;
import com.excilys.formation.projet.ebanking.webapp.flash.FlashScopeModifier;
import com.excilys.formation.projet.ebanking.webapp.security.CustomUser;

@Controller
@RequestMapping("/client/")
public class ClientController {

	@Autowired
	IClientService clientService;

	@Autowired
	ICompteService compteService;

	@Value("${monthPicker.nbMois}")
	int nbMoisMonthPicker;

	@RequestMapping("index.html")
	public String initClient(ModelMap model) {
		CustomUser utilisateur = (CustomUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

		model.addAttribute("comptes", clientService.getComptesByClient(utilisateur.getId()));
		model.addAttribute("identifiant", utilisateur.getUsername());

		return "client/listeCompte";
	}

	@RequestMapping("compte/{id}.html")
	public String getDetailsCompte(@PathVariable int id, ModelMap model) {

		DateTime date = new DateTime();

		return detailsCompte(model, id, date);
	}

	@RequestMapping("compte/{id}/{annee}/{mois}.html")
	public String getDetailsCompteMois(@PathVariable int id, @PathVariable int annee, @PathVariable int mois, ModelMap model) {
		if (mois > 12)
			throw new IllegalArgumentException("Argument interdit");

		DateTime date = new DateTime(annee, mois, 1, 0, 0, 0, 0);

		if (date.isAfterNow() || date.isBefore(new DateTime().minusMonths(nbMoisMonthPicker)))
			throw new AccessControlException("Accès interdit");

		return detailsCompte(model, id, date);
	}

	private String detailsCompte(ModelMap model, int id, DateTime date) {

		CustomUser utilisateur = (CustomUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

		Compte compte = compteService.getCompte(id);
		model.addAttribute("compte", compte);
		model.addAttribute("operationsNonCarte", clientService.getOperationsNonCarte(id, date, utilisateur.getId()));
		model.addAttribute("sommeOperationCarte", clientService.getSommeOperationsCarte(id, date, utilisateur.getId()));
		model.addAttribute("picker", new MonthPickerEnable(nbMoisMonthPicker, date.getYear(), date.getMonthOfYear()));

		DateTime now = new DateTime();
		if (date.getYear() == now.getYear() && date.getMonthOfYear() == now.getMonthOfYear()) {
			model.addAttribute("dateCartes", now);
		}
		else {
			DateTime dernierJourDuMois = date.dayOfMonth().withMaximumValue();
			model.addAttribute("dateCartes", dernierJourDuMois);
		}

		return "client/detailsCompte";
	}

	@RequestMapping("compte/{id}/carte.html")
	public String getDetailsCarte(@PathVariable int id, ModelMap model) {
		return detailsCarte(model, id, new DateTime());
	}

	@RequestMapping("compte/{id}/{annee}/{mois}/carte.html")
	public String getDetailsCarteDate(@PathVariable int id, @PathVariable int annee, @PathVariable int mois, ModelMap model) {
		if (mois > 12)
			throw new IllegalArgumentException("Argument interdit");

		DateTime date = new DateTime(annee, mois, 1, 0, 0, 0, 0);

		if (date.isAfterNow() || date.isBefore(new DateTime().minusMonths(nbMoisMonthPicker)))
			throw new AccessControlException("Accès interdit");

		return detailsCarte(model, id, date);
	}

	private String detailsCarte(ModelMap model, int id, DateTime date) {
		CustomUser utilisateur = (CustomUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

		Compte compte = compteService.getCompte(id);
		model.addAttribute("compte", compte);
		model.addAttribute("operationsCarte", clientService.getOperationsCarte(id, date, utilisateur.getId()));

		MonthPickerEnable monthPickerEnable = new MonthPickerEnable(nbMoisMonthPicker, date.getYear(), date.getMonthOfYear());
		monthPickerEnable.setFinUrl("/carte");
		model.addAttribute("picker", monthPickerEnable);

		return "client/detailsCarte";
	}

	@RequestMapping(value = "verifSolde.html", method = RequestMethod.GET)
	public @ResponseBody
	String verifSolde(@RequestParam double solde, @RequestParam int compteSource) {
		Compte oCompteSource = compteService.getCompte(compteSource);

		if (oCompteSource.getSoldeCourant() - solde < 0) {
			return "Vous êtes trop pauvre";
		}

		return "OK";
	}

	@RequestMapping("virement.html")
	public String getVirement(ModelMap model) {
		CustomUser utilisateur = (CustomUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		model.addAttribute("comptes", clientService.getComptesByClient(utilisateur.getId()));
		model.addAttribute("virement", new Virement());
		return "client/virement";
	}

	/**
	 * @param model
	 * @param request
	 * @param virement
	 * @return
	 */
	@RequestMapping("effectuerVirement.html")
	public String effectuerVirement(ModelMap model, ServletRequest request, @Valid Virement virement, BindingResult bindingResult) {
		CustomUser utilisateur = (CustomUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		model.addAttribute("comptes", clientService.getComptesByClient(utilisateur.getId()));

		if (bindingResult.hasErrors()) {
			return "client/virement";
		}

		Double montant = virement.getMontant().doubleValue();
		Compte compteSource = compteService.getCompte(virement.getIdCompteSource());
		Compte compteDestination = compteService.getCompte(virement.getIdCompteDestination());

		try {
			clientService.addVirementInterne(compteSource, compteDestination, montant, new DateTime());
		}
		catch (SoldeInsuffisantException e) {
			model.addAttribute("messageErreur", "Vous êtes trop pauvre");
			return "client/virement";
		}

		FlashScopeModifier.getFlashScopeModifier().put(request, "virementSuccess", "Votre virement a été effectué");

		return "redirect:index.html";
	}
}
